package com.yanqu.road.server.gameplayer.module.activity.turtle;

import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.turtle.config.TurtleModel;
import com.yanqu.road.entity.activity.turtle.config.TurtleTemplate;
import com.yanqu.road.entity.activity.turtle.data.TurtleGame;
import com.yanqu.road.entity.activity.turtle.data.TurtleUserData;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.entity.log.turtle.LogTurtleClear;
import com.yanqu.road.entity.log.turtle.LogTurtleStart;
import com.yanqu.road.logic.bussiness.activity.TurtleBusiness;
import com.yanqu.road.pb.activity.TurtleProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.ServerLanguageMgr;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.turtle.TurtleConfig;
import com.yanqu.road.server.manger.activity.turtle.TurtleMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.protocol.CrossProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.util.*;

/**
 * @Author : Cxp
 * @Time : 2024-09-09
 * @Description : 乌龟对对碰-Module
 */

public class TurtleModule extends GeneralModule {

    private TurtleUserData userData;

    public TurtleModule(GamePlayer player) {
        super(player);
    }

    public TurtleUserData getUserData() {
        return userData;
    }

    @Override
    public boolean loadData() {
        ActivityInfo activityInfo = TurtleMgr.getActivityInfo();
        if (ActivityMgr.activityInShowTime(activityInfo)) {
            userData = new TurtleBusiness().getTurtleUserData(activityInfo.getActivityId(), player.getUserId());
        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {
        if (userData != null) {
            if (userData.isInsertOption()) {
                new TurtleBusiness().addUserData(userData);
            } else if (userData.isUpdateOption()) {
                new TurtleBusiness().updateUserData(userData);
            }
        }
        return true;
    }

    @Override
    public void afterLogin() {
        activityReload();
    }

    /**
     * 重新加载活动，包括同步配置、初始化用户、同步用户
     */
    public void activityReload() {
        if (!SystemOpenMgr.systemOpen(player, eSystemId.Turtle.getValue())) {
            return;
        }

        TurtleConfig config = TurtleMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }
        syncConfig(config);
        initUserData(config.getActivityId());
        syncUserData();
    }

    /**
     * 同步配置，并发送给客户端
     *
     * @param config t_s_turtle_model
     */
    private void syncConfig(TurtleConfig config) {
        TurtleProto.TurtleConfigDataSyncMsg.Builder builder = TurtleProto.TurtleConfigDataSyncMsg.newBuilder();
        TurtleProto.TurtleConfigDataTemp.Builder inner = TurtleProto.TurtleConfigDataTemp.newBuilder();

        for (TurtleModel info : config.getModelMap().values()) {
            TurtleProto.TurtleModelTemp.Builder temp = TurtleProto.TurtleModelTemp.newBuilder();
            temp.setId(info.getId());
            temp.setText(ServerLanguageMgr.getContent(info.getText(), player.getLanguage()));
            temp.setDesc(ServerLanguageMgr.getContent(info.getDesc(), player.getLanguage()));
            temp.setScore(info.getScore());
            temp.setReward(info.getReward());
            temp.setTurtleCard(info.getTurtleCard());
            temp.setIsNotice(info.getIsNotice() != 0);
            temp.setWeight(info.getWeight() / 10);
            inner.addModelList(temp);
        }
        builder.setConfigData(inner);

        player.sendPacket(Protocol.U_TURTLE_CONFIG_DATA_SYNC, builder);
    }

    /**
     * 初始化用户
     *
     * @param activityId 活动ID
     */
    private synchronized void initUserData(int activityId) {
        if (userData == null || userData.getActivityId() != activityId) {
            TurtleUserData tempData = new TurtleUserData();
            tempData.setUserId(player.getUserId());
            tempData.setActivityId(activityId);
            tempData.setCurGame(new TurtleGame());
            tempData.setInsertOption();
            userData = tempData;
        }
    }

    /**
     * 同步用户
     */
    private void syncUserData() {
        if (userData == null) {
            return;
        }
        TurtleProto.TurtleUserDataSyncMsg.Builder builder = TurtleProto.TurtleUserDataSyncMsg.newBuilder();
        builder.setUserData(buildrRet(userData));

        player.sendPacket(Protocol.U_TURTLE_USER_DATA_SYNC, builder);
    }

    /**
     * 选择幸运色
     *
     * @param activityId 活动ID
     * @param color      幸运色
     * @return ret
     */
    public int chooseLuckyColor(int activityId, int color) {
        int check = check(activityId);
        if (check != 0) {
            return check;
        }

        if (userData.getIsPlaying()) { // 正在游戏中，不能进行颜色选择
            return GameErrorCode.E_TURTLE_CAN_NOT_CHANGE_LUCKY_COLOR;
        }
        if (color < TurtleConst.FIRST_COLOR || color > TurtleConst.LAST_COLOR) { // 1-10是有效颜色
            return GameErrorCode.E_TURTLE_INVALID_COLOR_PARAM;
        }

        TurtleGame game = userData.getCurGame();
        if (game == null) {
            game = new TurtleGame();
        }
        game.setLuckyColor(color);
        userData.setCurGame(game);
        TurtleProto.TurtleChooseLuckyColorResp.Builder builder = TurtleProto.TurtleChooseLuckyColorResp.newBuilder();
        builder.setRet(0);
        player.sendPacket(Protocol.U_TURTLE_CHOOSE_LUCKY_COLOR, builder);

        return 0;
    }

    /**
     * 执行逻辑分支
     *
     * @param activityId 活动ID
     * @param state      0-开局 1-续发 2-结束
     * @return ret
     */
    public int getGame(int activityId, int state) {
        int check = check(activityId);
        if (check != 0) {
            return check;
        }
        switch (state) {
            case TurtleConst.START:
                return start();
            case TurtleConst.NEXT:
                return next();
            case TurtleConst.OVER:
                return over();
            default:
                return GameErrorCode.E_TURTLE_INVALID_STATE_PARAM;
        }
    }

    /**
     * 开始
     *
     * @return ret
     */
    private int start() {
        if (userData.getIsPlaying()) { // 在游戏中不能开始
            return GameErrorCode.E_TURTLE_GAME_PLAYING;
        }

        TurtleConfig config = TurtleMgr.getConfig();
        CurrencyModule currencyModule = player.getModule(CurrencyModule.class);
        String costStr = config.getItemId() + "=" + config.getStartNum();
        Property cost = PropertyHelper.parseStringToProperty(costStr);
        if (!currencyModule.currencyIsEnough(cost)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        TurtleGame game = userData.getCurGame();
        if (game == null) {
            return GameErrorCode.E_TURTLE_GET_GAME_FAIL;
        }
        if (game.getLuckyColor() < TurtleConst.FIRST_COLOR || game.getLuckyColor() > TurtleConst.LAST_COLOR) { //
            // 1-10是有效颜色
            return GameErrorCode.E_TURTLE_INVALID_COLOR_PARAM;
        }
        TurtleUserData cloned = userData.clone();
        int ret = initGame(cloned);
        if (ret != 0) {
            return ret;
        }
        userData.copy(cloned);
        returnGameInfo();

        // 扣除龟龟奖券
        currencyModule.removeCurrency(cost, eLogMoneyType.Turtle, eLogMoneyType.TurtleCost);

        LogTurtleStart logStart = new LogTurtleStart();
        long serverId = GameServer.getInstance().getServerId();
        logStart.setChannelId(ServerListMgr.getChannelId(serverId));
        logStart.setServerId(serverId);
        logStart.setActivityId(userData.getActivityId());
        logStart.setUserId(player.getUserId());
        logStart.setRoundId(userData.getRoundCnt());
        logStart.setCost(costStr);
        logStart.setLogTime(new Date());
        AutoLogMgr.add(logStart);

        return 0;
    }

    /**
     * 初始化游戏数据
     *
     * @param user 用户信息
     * @return ret
     */
    private int initGame(TurtleUserData user) {
        TurtleGame game = user.getCurGame();
        user.setIsPlaying(true); // 设置游戏状态为 进行中
        user.setRoundCnt((user.getRoundCnt()) + 1);

        // 选择模板
        TurtleConfig config = TurtleMgr.getConfig();
        Map<Integer, TurtleTemplate> pool = config.getTemplateMap();
        int badTemplateCnt = user.getBadTemplateCnt();
        if (badTemplateCnt == config.getGuaranteeNum()) { // 保底触发，更换为好模板池
            pool = config.getGoodTemplateMap();
        }

        Map<Integer, Integer> weightMap = new HashMap<>();
        for (Map.Entry<Integer, TurtleTemplate> kv : pool.entrySet()) {
            weightMap.put(kv.getKey(), kv.getValue().getWeight());
        }

        RandomHelper rand = new RandomHelper();
        int templateId = rand.getRandomKeyByWeightEx(weightMap);

        // 除去幸运色，随机颜色
        int luckyColor = game.getLuckyColor();
        List<Integer> colors = new ArrayList<>();
        for (int i = TurtleConst.FIRST_COLOR; i <= TurtleConst.LAST_COLOR; i++) {
            if (i != luckyColor) {
                colors.add(i);
            }
        }
        Collections.shuffle(colors);
        colors.add(0, luckyColor);
        game.setColors(colors);

        // 设置当前局游戏模板信息
        TurtleTemplate template = pool.get(templateId);
        String[] layouts = template.getTemplate().split(";");
        game.setStartLayout(layouts[0]);
        game.setTemplateId(templateId);
        game.setTemplateIdx(1); // 模板第一个状态已默认处理，从第二开始
        String[] start = layouts[0].split("\\|");
        if (start.length != TurtleConst.LAYOUT_LEN) {
            log.error("模板布局长度错误! 模板ID:{} idx:{}", game.getTemplateId(), 0);
            return GameErrorCode.E_TURTLE_ACTIVITY_CONFIG_ERROR;
        }
        calculate(start, user);

        return 0;
    }

    /**
     * 续发
     *
     * @return ret
     */
    private int next() {
        if (!userData.getIsPlaying()) {
            return GameErrorCode.E_TURTLE_GAME_NOT_START;
        }

        TurtleGame game = userData.getCurGame();
        if (game == null) {
            return GameErrorCode.E_TURTLE_GET_GAME_FAIL;
        }

        TurtleUserData cloned = userData.clone();
        game = cloned.getCurGame();
        TurtleTemplate template = TurtleMgr.getConfig().getTemplateMap().get(game.getTemplateId());
        String[] layouts = template.getTemplate().split(";");

        int templateIdx = game.getTemplateIdx();
        game.setStartLayout(layouts[templateIdx]);
        String[] start = layouts[templateIdx].split("\\|");
        if (start.length != TurtleConst.LAYOUT_LEN) {
            log.error("模板布局长度错误! 模板ID:{} idx:{}", game.getTemplateId(), templateIdx);
            return GameErrorCode.E_TURTLE_ACTIVITY_CONFIG_ERROR;
        }
        calculate(start, cloned);
        if (templateIdx < layouts.length - 1) {
            game.setTemplateIdx(game.getTemplateIdx() + 1); // 未到最后一个状态时，记录下一个状态
        } else if (templateIdx == layouts.length - 1) {
            if (game.getCardNum() > 0) {
                log.error("卡包未被清零! 模板ID:{} 流程存在错误!", game.getTemplateId());
                return GameErrorCode.E_TURTLE_ACTIVITY_CONFIG_ERROR;
            }
        }

        userData.copy(cloned);
        returnGameInfo();

        return 0;
    }

    /**
     * 返回当前轮结果，并更新排行榜和个人成就任务
     */
    private void returnGameInfo() {
        TurtleProto.TurtleGameResp.Builder builder = TurtleProto.TurtleGameResp.newBuilder();
        builder.setRet(0);
        builder.setUserData(buildrRet(userData));
        player.sendPacket(Protocol.U_TURTLE_GET_GAME, builder);

        boolean needNotify = true;
        ActivityInfo activityInfo = TurtleMgr.getActivityInfo();
        if (ActivityMgr.activityInRewardPeriod(activityInfo)) { // 领奖期不更新排行榜
            needNotify = false;
        }
        if (needNotify) {
            player.notifyListener(eGamePlayerEventType.TurtleUserRank.getValue(), userData.getScore()); // 更新排行榜
        }
        player.notifyListener(eGamePlayerEventType.TurtleUserAchievement.getValue(), userData.getScore()); // 更新个人成就任务
    }

    /**
     * 结束
     *
     * @return ret
     */
    private int over() {
        if (!userData.getIsPlaying()) {
            return GameErrorCode.E_TURTLE_GAME_NOT_START;
        }

        TurtleGame game = userData.getCurGame();
        if (game == null) {
            return GameErrorCode.E_TURTLE_GET_GAME_FAIL;
        }

        TurtleConfig config = TurtleMgr.getConfig();
        userData.setIsPlaying(false);

        // 计算奖励
        Map<Integer, Integer> rewards = new HashMap<>();
        for (Map<Integer, Integer> map : game.getTotalResult().values()) {
            for (Map.Entry<Integer, Integer> kv : map.entrySet()) {
                String rewardStr = config.getModelMap().get(kv.getKey()).getReward(); // 124122=1;124123=2
                if (StringUtils.isNullOrEmpty(rewardStr) || rewardStr.equals("0")) {
                    continue;
                }
                String[] items = rewardStr.split(";"); // 124122=1 124123=2
                for (String item : items) {
                    String[] pairs = item.split("="); // 124122 1
                    int goodsId = Integer.parseInt(pairs[0]);
                    int cnt = Integer.parseInt(pairs[1]) * kv.getValue();
                    rewards.put(goodsId, rewards.getOrDefault(goodsId, 0) + cnt);
                }
            }
        }

        Property reward = new Property();
        for (Map.Entry<Integer, Integer> kv : rewards.entrySet()) {
            int goodsId = kv.getKey();
            int cnt = kv.getValue();
            reward.addProperty(goodsId, cnt);
        }
        player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.Turtle, eLogMoneyType.TurtleReward);

        TurtleProto.TurtleGameResp.Builder builder = TurtleProto.TurtleGameResp.newBuilder();
        String rewardStr = reward.toHelperString();
        if (!rewardStr.contains(String.valueOf(config.getGoldId()))) { // 不包含金龟勋章，保底加1
            userData.setBadTemplateCnt(userData.getBadTemplateCnt() + 1);
        }
        builder.setReward(rewardStr);
        builder.setRet(0);

        // 保留幸运色选择
        int luckyColor = game.getLuckyColor();
        game = new TurtleGame();
        game.setLuckyColor(luckyColor);
        userData.setCurGame(game);
        builder.setUserData(buildrRet(userData));
        player.sendPacket(Protocol.U_TURTLE_GET_GAME, builder);

        LogTurtleClear logClear = new LogTurtleClear();
        long serverId = GameServer.getInstance().getServerId();
        logClear.setChannelId(ServerListMgr.getChannelId(serverId));
        logClear.setServerId(serverId);
        logClear.setActivityId(userData.getActivityId());
        logClear.setUserId(player.getUserId());
        logClear.setRoundId(userData.getRoundCnt());
        logClear.setResult(new ArrayList<>());
        logClear.setReward(reward.toHelperString());
        logClear.setLogTime(new Date());
        AutoLogMgr.add(logClear);

        return 0;
    }

    /**
     * 计算偏移后的位置，0不参与取模运算，提前去除最后再+1表示从1开始
     *
     * @param pos 原有位置
     * @return 偏移后位置
     */
    private int modifyPos(int pos) {
        return ((pos <= 0 ? pos + 8 : pos) - 1) % 8 + 1;
    }

    /**
     * 核心逻辑，计算一轮游戏的消除结果
     *
     * @param start 开始的布局
     * @param user  用户信息
     */
    private void calculate(String[] start, TurtleUserData user) {
        TurtleGame game = user.getCurGame();
        int lucky = 0; // 是否有中心幸运色
        int isFull = 1; // 是否满台
        int isClear = 1; // 是否清台
        int cardNum = game.getCardNum(); // 卡包剩余
        long score = 0; // 个人总得分
        boolean isCenterClear = false; // 中心位置是否要清除
        List<String> ones = new ArrayList<>(); // 幸运色位置
        List<List<String>> twos = new ArrayList<>(); // 对碰位置
        List<List<String>> threes = new ArrayList<>(); // 三连位置
        List<List<String>> fours = new ArrayList<>(); // 四连位置
        Map<Integer, Map<Integer, Integer>> colorTypeCnt = new HashMap<>();
        LogTurtleClear logClear = new LogTurtleClear();

        // 统计消除类型
        String lastEndLayout = game.getEndLayout();
        int logCardNum = cardNum;
        if (!StringUtils.isNullOrEmpty(lastEndLayout)) { // 上轮结束不为空，表示这不是第一轮
            String[] lastEnd = lastEndLayout.split("\\|");
            for (int i = TurtleConst.ZERO; i <= TurtleConst.EIGHT; i++) {
                if (lastEnd[i].equals(TurtleConst.EMPTY) && cardNum > 0) { // 根据上轮结果的空格数，扣除相应卡包
                    cardNum--;
                }

                String curColor = start[i];
                // 当前位置是幸运色且上轮结束不为幸运色，避免幸运色未被消除反复统计到结果中
                if (TurtleConst.LUCKY_COLOR.equals(curColor) && !lastEnd[i].equals(curColor)) {
                    if (i == TurtleConst.ZERO) {
                        lucky = 1; // 一号位幸运色
                        continue; // 不需要将其添加到幸运色的位置结果中
                    }
                    ones.add(String.valueOf(i));
                    recordColorTypeCnt(curColor, colorTypeCnt, TurtleConst.LUCKY);
                }
            }
        } else {
            lucky = start[TurtleConst.ZERO].equals(TurtleConst.LUCKY_COLOR) ? 1 : 0; // 一号位幸运色单独判断
            for (int i = TurtleConst.ONE; i <= TurtleConst.EIGHT; i++) {
                String curColor = start[i];
                if (TurtleConst.LUCKY_COLOR.equals(curColor)) {
                    ones.add(String.valueOf(i));
                    recordColorTypeCnt(curColor, colorTypeCnt, TurtleConst.LUCKY);
                }
            }
        }
        logClear.setCardCost(logCardNum - cardNum);
        logCardNum = cardNum;

        if (lucky == 1) {
            int color = Integer.parseInt(TurtleConst.LUCKY_COLOR);
            colorTypeCnt.put(color, new HashMap<>());
            colorTypeCnt.get(color).put(TurtleConst.LUCKY_ONE, 1);
        }

        // 外圈四连
        // 先逆时针判断1234 到 6781
        for (int k = TurtleConst.ONE; k >= TurtleConst.NEG_TWO; k--) { // 由1到-2即1 0 -1 -2，对应1 8 7 6
            recordPos(modifyPos(k), TurtleConst.OFF_THREE, start, fours, colorTypeCnt, TurtleConst.QUADRA);
        }

        // 再顺时针判断2345 到 5678
        for (int i = TurtleConst.TWO; i <= TurtleConst.FIVE; i++) {
            recordPos(i, TurtleConst.OFF_THREE, start, fours, colorTypeCnt, TurtleConst.QUADRA);
        }

        // 直线三连
        for (int i = TurtleConst.ONE; i <= TurtleConst.FOUR; i++) {
            String curColor = start[i];
            if (!curColor.equals(TurtleConst.EMPTY) && curColor.equals(start[TurtleConst.ZERO])
                    && curColor.equals(start[i + TurtleConst.OFF_FOUR])) {
                List<String> tmp = new ArrayList<>();
                tmp.add(String.valueOf(i));
                start[i] = TurtleConst.EMPTY;
                tmp.add(String.valueOf(TurtleConst.ZERO));
                tmp.add(String.valueOf(modifyPos(i + TurtleConst.OFF_FOUR)));
                start[i + TurtleConst.OFF_FOUR] = TurtleConst.EMPTY;
                isCenterClear = true;
                threes.add(tmp);
                recordColorTypeCnt(curColor, colorTypeCnt, TurtleConst.TRIPLE);
            }
        }

        // 外圈三连
        // 先逆时针判断123 到 781
        for (int k = TurtleConst.ONE; k >= TurtleConst.NEG_ONE; k--) {
            recordPos(modifyPos(k), TurtleConst.OFF_TWO, start, threes, colorTypeCnt, TurtleConst.TRIPLE);
        }

        // 再顺时针判断234 到 678
        for (int i = TurtleConst.TWO; i <= TurtleConst.SIX; i++) {
            recordPos(i, TurtleConst.OFF_TWO, start, threes, colorTypeCnt, TurtleConst.TRIPLE);
        }

        // 包含中心的二连
        for (int i = TurtleConst.ONE; i <= TurtleConst.EIGHT; i++) {
            String curColor = start[i];
            if (!curColor.equals(TurtleConst.EMPTY) && start[TurtleConst.ZERO].equals(curColor)) {
                List<String> tmp = new ArrayList<>();
                tmp.add(String.valueOf(TurtleConst.ZERO));
                tmp.add(String.valueOf(i));
                start[i] = TurtleConst.EMPTY;
                twos.add(tmp);
                isCenterClear = true;
                int color = Integer.parseInt(curColor);
                if (!colorTypeCnt.containsKey(color)) {
                    colorTypeCnt.put(color, new HashMap<>());
                }
                recordColorTypeCnt(curColor, colorTypeCnt, TurtleConst.DOUBLE);
            }
        }

        // 不包含中心的二连
        for (int i = TurtleConst.ONE; i <= TurtleConst.SEVEN; i++) {
            String curColor = start[i];
            if (curColor.equals(TurtleConst.EMPTY)) {
                continue;
            }
            for (int j = i + 1; j <= TurtleConst.EIGHT; j++) {
                if (curColor.equals(start[j])) {
                    List<String> tmp = new ArrayList<>();
                    tmp.add(String.valueOf(i));
                    start[i] = TurtleConst.EMPTY;
                    tmp.add(String.valueOf(j));
                    start[j] = TurtleConst.EMPTY;
                    twos.add(tmp);
                    recordColorTypeCnt(curColor, colorTypeCnt, TurtleConst.DOUBLE);
                    break;
                }
            }
        }

        if (isCenterClear) { // 中心要在最后判断消除
            start[TurtleConst.ZERO] = TurtleConst.EMPTY;
        }

        for (int i = TurtleConst.ZERO; i <= TurtleConst.EIGHT; i++) { // 判断清台和满台
            if (!start[i].equals(TurtleConst.EMPTY)) { // 有非空则不是清台
                isClear = 0;
            } else { // 有空则不是满台
                isFull = 0;
            }
        }

        // 统计当前轮结果
        Map<Integer, String> roundResult = new HashMap<>();
        Map<Integer, Integer> typeCnt = new HashMap<>();
        String positions = getPositions(twos);
        if (!StringUtils.isNullOrEmpty(positions)) {
            roundResult.put(TurtleConst.DOUBLE, positions);
            typeCnt.put(TurtleConst.DOUBLE, twos.size());
        }
        positions = getPositions(threes);
        if (!StringUtils.isNullOrEmpty(positions)) {
            roundResult.put(TurtleConst.TRIPLE, positions);
            typeCnt.put(TurtleConst.TRIPLE, threes.size());
        }
        positions = getPositions(fours);
        if (!StringUtils.isNullOrEmpty(positions)) {
            roundResult.put(TurtleConst.QUADRA, positions);
            typeCnt.put(TurtleConst.QUADRA, fours.size());
        }
        if (isClear == 1) {
            roundResult.put(TurtleConst.CLEAR, "");
            typeCnt.put(TurtleConst.CLEAR, isClear);
            colorTypeCnt.put(TurtleConst.NO_COLOR, new HashMap<Integer, Integer>() {{put(TurtleConst.CLEAR, 1);}});
        }
        positions = String.join(";", ones);
        if (!StringUtils.isNullOrEmpty(positions)) {
            roundResult.put(TurtleConst.LUCKY, positions);
            typeCnt.put(TurtleConst.LUCKY, ones.size());
        }
        if (lucky == 1) {
            roundResult.put(TurtleConst.LUCKY_ONE, "0");
            typeCnt.put(TurtleConst.LUCKY_ONE, lucky);
        }

        // 统计全部轮结果
        List<Integer> logResult = new ArrayList<>();
        List<TurtleProto.TurtleNoticeDataTemp> uploadList = new ArrayList<>();
        TurtleConfig config = TurtleMgr.getConfig();
        Map<Integer, TurtleModel> modelMap = config.getModelMap();
        for (Map.Entry<Integer, TurtleModel> kv : modelMap.entrySet()) {
            int typeId = kv.getKey();
            TurtleModel model = kv.getValue();
            int num = typeCnt.getOrDefault(typeId, 0);
            cardNum += model.getTurtleCard() * num;
            score += (long) model.getScore() * num;
            if (num > 0 && model.getReward().contains(String.valueOf(config.getGoldId()))) { // 抽到金龟勋章，重置保底
                user.setBadTemplateCnt(0);
            }

            if (num > 0 && model.getIsNotice() == 1) { // 记录需要发公告的消息
                logClear.setNotice(true);
                for (int i = 0; i < num; i++) {
                    uploadList.add(buildNotice(typeId == TurtleConst.CLEAR ?
                            String.valueOf(model.getTurtleCard()) : model.getReward(), typeId)); // 清台发卡包数，其它的发奖励
                }
            }
            for (int i = 0; i < num; i++) {
                logResult.add(typeId);
            }
        }
        logClear.setResult(logResult);

        if (isFull == 1 && cardNum > 0) { // 满台且不是卡包为0（结束），去除中心位置
            roundResult.put(TurtleConst.FULL, "0");
            start[TurtleConst.ZERO] = TurtleConst.EMPTY;
        }

        user.setScore(user.getScore() + score);
        Property scoreReward = new Property(TurtleMgr.getConfig().getScoreId(), score);
        player.getModule(CurrencyModule.class).addCurrency(scoreReward, eLogMoneyType.Turtle,
                eLogMoneyType.TurtleScoreGet);
        game.setCardNum(cardNum);
        game.setEndLayout(String.join("|", start));
        game.setRoundResult(roundResult);
        Map<Integer, Map<Integer, Integer>> totalResult = game.getTotalResult();
        for (Map.Entry<Integer, Map<Integer, Integer>> kv : colorTypeCnt.entrySet()) {
            int color = kv.getKey(); // 颜色id
            for (Map.Entry<Integer, Integer> kv1 : colorTypeCnt.get(color).entrySet()) {
                int type = kv1.getKey();
                int num = kv1.getValue();
                if (!totalResult.containsKey(color)) {
                    totalResult.put(color, new HashMap<>());
                }
                totalResult.get(color).merge(type, num, Integer::sum);
            }
        }
        game.setTotalResult(totalResult);

        if (!uploadList.isEmpty()) { // 上传公告
            TurtleProto.CrossTurtleUploadNoticeReq.Builder upload = TurtleProto.CrossTurtleUploadNoticeReq.newBuilder();
            upload.setActivityId(user.getActivityId());
            upload.addAllNoticeData(uploadList);
            player.sendPacket(CrossProtocol.C_TURTLE_UPLOAD_NOTICE, upload);
        }

        long serverId = GameServer.getInstance().getServerId();
        logClear.setChannelId(ServerListMgr.getChannelId(serverId));
        logClear.setServerId(serverId);
        logClear.setActivityId(user.getActivityId());
        logClear.setUserId(player.getUserId());
        logClear.setRoundId(user.getRoundCnt());
        logClear.setScore(score);
        logClear.setCardGet(cardNum - logCardNum);
        logClear.setLogTime(new Date());
        AutoLogMgr.add(logClear);
    }

    private static void recordColorTypeCnt(String curColor, Map<Integer, Map<Integer, Integer>> colorTypeCnt,
                                           int type) {
        int color = Integer.parseInt(curColor);
        if (!colorTypeCnt.containsKey(color)) {
            colorTypeCnt.put(color, new HashMap<>());
        }
        colorTypeCnt.get(color).merge(type, 1, Integer::sum);
    }

    /**
     * 获取消除结果的位置
     *
     * @param idx    位置下标
     * @param range  范围
     * @param layout 布局
     * @param list   list
     */
    private void recordPos(int idx, int range, String[] layout, List<List<String>> list, Map<Integer, Map<Integer,
            Integer>> colorTypeCnt, int type) {
        String curColor = layout[idx];
        boolean flg = true;

        if (!curColor.equals(TurtleConst.EMPTY)) {
            for (int j = TurtleConst.OFF_ZERO; j <= range; j++) {
                int pos = modifyPos(idx + j);
                if (!curColor.equals(layout[pos])) {
                    flg = false;
                    break;
                }
            }

            if (flg) {
                List<String> tmp = new ArrayList<>();
                for (int j = TurtleConst.OFF_ZERO; j <= range; j++) {
                    int pos = modifyPos(idx + j);
                    tmp.add(String.valueOf(pos));
                    layout[pos] = TurtleConst.EMPTY;
                }
                list.add(tmp);
                recordColorTypeCnt(curColor, colorTypeCnt, type);
            }
        }
    }

    /**
     * 构建公告信息返回
     *
     * @param reward 奖励
     * @param type   消除类型
     * @return TurtleNoticeDataTemp
     */
    private TurtleProto.TurtleNoticeDataTemp buildNotice(String reward, int type) {
        TurtleProto.TurtleNoticeDataTemp.Builder builder = TurtleProto.TurtleNoticeDataTemp.newBuilder();
        builder.setActivityId(userData.getActivityId());
        builder.setUserId(userData.getUserId());
        builder.setServerId(GameServer.getInstance().getServerId());
        builder.setNickName(player.getUserInfo().getNickName());
        builder.setType(type);
        builder.setReward(reward);
        builder.setTime(System.currentTimeMillis());

        return builder.build();
    }

    /**
     * 获取位置字符串
     *
     * @param params 参数
     * @return 如 1|2|3;4|5|6
     */
    private String getPositions(List<List<String>> params) {
        int size = params.size();
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < size; i++) {
            sb.append(String.join("|", params.get(i)));
            if (i != size - 1) {
                sb.append(";");
            }
        }

        return sb.toString();
    }

    /**
     * 跨服获取公告
     *
     * @param reqMsg 请求
     * @return ret
     */
    public int getNotice(TurtleProto.TurtleNoticeMsgReq reqMsg) {
        if (reqMsg == null) {
            return GameErrorCode.E_TURTLE_GET_NOTICE_FAIL;
        }
        int check = check(reqMsg.getActivityId());
        if (check != 0) {
            return check;
        }
        player.sendPacket(CrossProtocol.C_TURTLE_GET_NOTICE, reqMsg.toBuilder());

        return 0;
    }

    /**
     * 简单检查
     *
     * @param activityId 活动ID
     * @return ret
     */
    public int check(int activityId) {
        ActivityInfo activityInfo = TurtleMgr.getActivityInfo();
        if (activityInfo == null) {
            return GameErrorCode.E_TURTLE_ACTIVITY_NOT_OPEN;
        }
        if (activityInfo.getActivityId() != activityId) {
            return GameErrorCode.E_TURTLE_ACTIVITY_ID_ERROR;
        }

        if (!ActivityMgr.activityInShowTime(activityInfo)) {
            return GameErrorCode.E_TURTLE_ACTIVITY_NO_IN_SHOW_TIME;
        }
        if (!SystemOpenMgr.systemOpen(player, eSystemId.Turtle.getValue())) {
            return GameErrorCode.E_TURTLE_ACTIVITY_LOCK;
        }
        TurtleConfig config = TurtleMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_TURTLE_ACTIVITY_CONFIG_ERROR;
        }
        if (userData == null || userData.getActivityId() != activityId) {
            initUserData(activityId);
        }
        if (userData == null || userData.getActivityId() != activityId) {
            return GameErrorCode.E_TURTLE_ACTIVITY_NOT_OPEN;
        }

        return 0;
    }

    /**
     * 构建用户信息返回
     *
     * @param userData 用户信息
     * @return TurtleUserDataTemp
     */
    private TurtleProto.TurtleUserDataTemp.Builder buildrRet(TurtleUserData userData) {
        TurtleProto.TurtleUserDataTemp.Builder builder = TurtleProto.TurtleUserDataTemp.newBuilder();

        builder.setScore(userData.getScore());
        builder.setNumToGood(TurtleMgr.getConfig().getGuaranteeNum() - userData.getBadTemplateCnt());
        builder.setRoundCnt(userData.getRoundCnt());
        builder.setIsPlaying(userData.getIsPlaying());

        TurtleGame game = userData.getCurGame();
        if (game != null) {
            TurtleProto.TurtleCurGameTemp.Builder builder1 = TurtleProto.TurtleCurGameTemp.newBuilder();
            builder1.setLuckyColor(game.getLuckyColor());
            builder1.setCardNum(game.getCardNum());
            builder1.setStart(game.getStartLayout());
            builder1.setEnd(game.getEndLayout());
            builder1.addAllColors(game.getColors());

            for (Map.Entry<Integer, String> kv : game.getRoundResult().entrySet()) {
                TurtleProto.TurtleResultTemp.Builder builder2 = TurtleProto.TurtleResultTemp.newBuilder();
                builder2.setType(kv.getKey());
                builder2.setPositions(kv.getValue());
                builder1.addResultList(builder2);
            }

            for (Map.Entry<Integer, Map<Integer, Integer>> kv : game.getTotalResult().entrySet()) {
                int color = kv.getKey();
                for (Map.Entry<Integer, Integer> kv1 : kv.getValue().entrySet()) {
                    TurtleProto.TurtleCountTemp.Builder builder3 = TurtleProto.TurtleCountTemp.newBuilder();
                    builder3.setColor(color);
                    builder3.setType(kv1.getKey());
                    builder3.setNum(kv1.getValue());
                    builder1.addCountList(builder3);
                }
            }

            builder.setCurGame(builder1);
        }

        return builder;
    }
}
